#include "interrupt.h"
#include "pmm.h"
#include "printf.h"
#include "panic.h"
#include "plic.h"
#include "clint.h"
#include "riscv.h"
#include "vmm.h"  // 新增：用于异常处理中的地址解析

// 声明汇编实现的中断入口函数
extern void trap_entry(void);

// 全局中断向量表实例（存储所有中断的处理信息）
irq_descriptor_t irq_vector_table[MAX_IRQ_NUM] = {0};

/**
 * 初始化中断系统核心函数
 *  - 清空中断向量表
 *  - 配置中断入口地址
 *  - 初始化硬件中断控制器（PLIC/CLINT）
 *  - 使能全局中断
 */
void trap_init(void) {
    // 1. 初始化中断向量表（默认禁用所有中断，清空处理函数）
    for (int i = 0; i < MAX_IRQ_NUM; i++) {
        irq_vector_table[i].handler_count = 0;
        irq_vector_table[i].priority = IRQ_PRIORITY_0;
        irq_vector_table[i].enabled = 0;
        for (int j = 0; j < MAX_HANDLERS_PER_IRQ; j++) {
            irq_vector_table[i].handlers[j] = NULL;
        }
    }

    // 2. 配置中断入口（RISC-V mtvec寄存器：直接模式）
    // 直接模式：所有中断/异常都跳转到trap_entry
    uint64_t trap_entry_addr = (uint64_t)trap_entry;
    w_mtvec(trap_entry_addr | MTVEC_DIRECT);  // 使用宏增强可读性

    // 3. 初始化硬件中断控制器
    plic_init();    // 初始化平台级中断控制器
    clint_init();   // 初始化核心本地时钟中断控制器

    // 4. 使能M模式全局中断（MIE位）
    w_mstatus(r_mstatus() | MSTATUS_MIE);

    // 5. 使能M模式外部中断和时钟中断（PLIC和CLINT）
    w_mie(r_mie() | MIE_MEIE | MIE_MTIE);

    printf("中断系统初始化完成（支持时钟和外部设备中断）\n");
}

/**
 * 注册中断处理函数
 * @param irq：中断号（IRQ_TIMER/IRQ_UART等）
 * @param h：处理函数指针
 * @param prio：中断优先级（0-7，7最高）
 * @return 0成功，-1参数无效或处理函数已满
 */
int register_interrupt(irq_num_t irq, interrupt_handler_t h, irq_priority_t prio) {
    // 参数合法性检查
    if (irq >= MAX_IRQ_NUM || h == NULL || prio > IRQ_PRIORITY_7) {
        printf("注册中断失败：无效参数（irq=%d, prio=%d）\n", irq, prio);
        return -1;
    }

    irq_descriptor_t *desc = &irq_vector_table[irq];
    // 检查处理函数数量是否已满
    if (desc->handler_count >= MAX_HANDLERS_PER_IRQ) {
        printf("注册中断失败：IRQ%d处理函数数量已满（最大%d个）\n", irq, MAX_HANDLERS_PER_IRQ);
        return -1;
    }

    // 添加处理函数并更新优先级（取最高优先级）
    desc->handlers[desc->handler_count++] = h;
    if (prio > desc->priority) {
        desc->priority = prio;
        plic_set_priority(irq, prio);  // 同步更新PLIC硬件优先级
    }

    printf("注册中断成功：IRQ%d（优先级%d，当前处理函数数：%d）\n", 
           irq, prio, desc->handler_count);
    return 0;
}

/**
 * 注销中断处理函数
 * @param irq：中断号
 * @param h：要注销的处理函数
 * @return 0成功，-1未找到或参数无效
 */
int unregister_interrupt(irq_num_t irq, interrupt_handler_t h) {
    if (irq >= MAX_IRQ_NUM || h == NULL) {
        return -1;
    }

    irq_descriptor_t *desc = &irq_vector_table[irq];
    for (int i = 0; i < desc->handler_count; i++) {
        if (desc->handlers[i] == h) {
            // 移除函数（用最后一个函数覆盖当前位置，减少计数）
            desc->handlers[i] = desc->handlers[desc->handler_count - 1];
            desc->handlers[desc->handler_count - 1] = NULL;
            desc->handler_count--;
            printf("注销中断成功：IRQ%d（剩余处理函数数：%d）\n", irq, desc->handler_count);
            return 0;
        }
    }

    printf("注销中断失败：IRQ%d未找到处理函数\n", irq);
    return -1;
}

/**
 * 使能特定中断
 * @param irq：中断号
 */
void enable_interrupt(irq_num_t irq) {
    if (irq >= MAX_IRQ_NUM) {
        printf("使能中断失败：无效IRQ%d\n", irq);
        return;
    }

    irq_descriptor_t *desc = &irq_vector_table[irq];
    if (desc->enabled) {
        return;  // 已使能，无需重复操作
    }

    // 更新使能标记并配置硬件
    desc->enabled = 1;
    if (irq == IRQ_TIMER) {
        // 时钟中断：使能M模式定时器中断位
        w_mie(r_mie() | MIE_MTIE);
    } else {
        // 外部中断：通过PLIC使能到当前HART
        plic_enable(irq, r_mhartid());
    }
    printf("使能中断：IRQ%d\n", irq);
}

/**
 * 禁用特定中断
 * @param irq：中断号
 */
void disable_interrupt(irq_num_t irq) {
    if (irq >= MAX_IRQ_NUM) {
        printf("禁用中断失败：无效IRQ%d\n", irq);
        return;
    }

    irq_descriptor_t *desc = &irq_vector_table[irq];
    if (!desc->enabled) {
        return;  // 已禁用，无需重复操作
    }

    // 更新使能标记并配置硬件
    desc->enabled = 0;
    if (irq == IRQ_TIMER) {
        // 时钟中断：禁用M模式定时器中断位
        w_mie(r_mie() & ~MIE_MTIE);
    } else {
        // 外部中断：通过PLIC禁用
        plic_disable(irq, r_mhartid());
    }
    printf("禁用中断：IRQ%d\n", irq);
}

/**
 * 解析异常原因并打印详细信息（辅助函数）
 * @param cause：异常原因（来自mcause寄存器）
 * @param epc：异常发生时的指令地址（来自mepc寄存器）
 */
static void handle_exception(uint64_t cause, uint64_t epc) {
    printf("\n===== 异常详情 =====\n");
    printf("异常原因代码：0x%lx\n", cause);
    printf("异常发生地址：0x%lx（虚拟地址）\n", epc);
    
    // 解析常见异常类型（参考RISC-V特权架构手册）
    switch (cause) {
        case 0:  printf("异常类型：指令地址未对齐\n"); break;
        case 1:  printf("异常类型：指令访问故障\n"); break;
        case 2:  printf("异常类型：非法指令\n"); break;
        case 5:  printf("异常类型：加载地址未对齐\n"); break;
        case 6:  printf("异常类型：加载访问故障\n"); break;
        case 7:  printf("异常类型：存储/AMO地址未对齐\n"); break;
        case 8:  printf("异常类型：存储/AMO访问故障\n"); break;
        case 12: printf("异常类型：指令页错误\n"); break;
        case 13: printf("异常类型：加载页错误\n"); break;
        case 15: printf("异常类型：存储/AMO页错误\n"); break;
        default: printf("异常类型：未知（请查阅RISC-V手册）\n");
    }
    printf("====================\n");
}

/**
 * 中断/异常处理核心逻辑（由汇编入口函数调用）
 * @param cause：中断/异常原因（来自mcause寄存器）
 * @param epc：中断/异常发生时的指令地址（来自mepc寄存器）
 */
void trap_handler(uint64_t cause, uint64_t epc) {
    // 区分异常（0）和中断（1 << 63）
    if ((cause & (1ULL << 63)) == 0) {
        // 处理异常
        handle_exception(cause, epc);
        panic("未处理的异常（系统终止）");
        return;
    }

    // 处理中断（提取低63位作为中断号）
    uint64_t irq = cause & ~(1ULL << 63);
    irq_descriptor_t *desc = NULL;
    uint32_t plic_irq = 0;  // PLIC中断号缓存

    switch (irq) {
        case 7:  // M模式时钟中断（CLINT）
            desc = &irq_vector_table[IRQ_TIMER];
            break;
        
        case 11: // M模式外部中断（PLIC）
            // 从PLIC获取具体中断号（硬件中断源）
            plic_irq = plic_claim(r_mhartid());
            // 检查中断号合法性（PLIC返回0表示无待处理中断）
            if (plic_irq == 0) {
                printf("警告：PLIC无待处理中断，但收到外部中断信号\n");
                return;
            }
            // 映射到IRQ_NUM（需与interrupt.h中定义一致）
            if (plic_irq + 1 < MAX_IRQ_NUM) {
                desc = &irq_vector_table[plic_irq + 1];
            } else {
                printf("警告：PLIC中断号%d超出向量表范围（最大%d）\n", 
                       plic_irq, MAX_IRQ_NUM - 2);
                plic_complete(r_mhartid(), plic_irq);  // 避免死锁，强制标记完成
                return;
            }
            break;
        
        default:
            printf("未知中断：cause=0x%lx（irq=%ld）\n", cause, irq);
            panic("未处理的中断类型");
            return;
    }

    // 执行中断处理函数（支持共享中断）
    if (desc && desc->enabled) {
        // 中断嵌套控制：仅允许更高优先级中断打断当前处理
        uint32_t current_prio = desc->priority;
        plic_set_threshold(r_mhartid(), current_prio);  // 屏蔽同/低优先级

        // 调用所有注册的处理函数
        for (int i = 0; i < desc->handler_count; i++) {
            if (desc->handlers[i]) {
                desc->handlers[i]();
            }
        }

        // 恢复优先级阈值（允许所有优先级中断）
        plic_set_threshold(r_mhartid(), 0);
    }

    // 通知PLIC中断处理完成（仅外部中断）
    if (irq == 11) {
        plic_complete(r_mhartid(), plic_irq);  // 传入实际的PLIC中断号
    }
}
